package top.zsyle.sycc.service.impl;

import bo.CourseOrderPayBo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import top.zsyle.sycc.domain.Course;
import top.zsyle.sycc.domain.CourseMarket;
import top.zsyle.sycc.domain.CourseOrder;
import top.zsyle.sycc.domain.CourseOrderItem;
import top.zsyle.sycc.dto.CourseOrderDto;
import top.zsyle.sycc.exception.GlobalExceptionEnum;
import top.zsyle.sycc.feign.CourseService;
import top.zsyle.sycc.mapper.CourseOrderMapper;
import top.zsyle.sycc.result.JsonResult;
import top.zsyle.sycc.service.ICourseOrderItemService;
import top.zsyle.sycc.service.ICourseOrderService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import top.zsyle.sycc.utils.AssertUtil;
import top.zsyle.sycc.utils.CodeGenerateUtils;
import top.zsyle.sycc.vo.CourseInfoVo;
import top.zsyle.sycc.vo.CourseOrderInfoVo;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhongshiyi
 * @since 2023-01-09
 */
@Service
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private CourseService courseService;
    @Autowired
    private ICourseOrderItemService courseOrderItemService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 提交订单
     * @param courseOrderDto
     * @return
     */
    @Override
    public String placeOrder(CourseOrderDto courseOrderDto) {
        Long loginId = 7L;
        List<Long> courseIds = courseOrderDto.getCourseIds();
        String idsStr = courseIds.stream().map(String::valueOf).collect(Collectors.joining(","));
        Integer payType = courseOrderDto.getPayType();
        String token = courseOrderDto.getToken();
        String key = loginId+":"+idsStr;
        Object o = redisTemplate.opsForValue().get(key);
        // 1.参数校验，使用JSR303
        // 2.业务校验
        // 2.1.判断是否是第一次进入
        AssertUtil.isNotNull(o, GlobalExceptionEnum.ERROR);
        // 2.2.判断令牌是否相等
        String value = JSON.parseObject(JSON.toJSONString(o), String.class);
        AssertUtil.isEquals(token,value,GlobalExceptionEnum.ERROR);
        redisTemplate.delete(key);
        // 2.3.根据课程Ids查询课程信息以及课程的market信息和总价，并且做了参数校验
        JsonResult info = courseService.info(idsStr);
        AssertUtil.isTrue(info.isSuccess(), GlobalExceptionEnum.ERROR);
        Object infoTmp = info.getData();
        AssertUtil.isNotNull(infoTmp, GlobalExceptionEnum.ERROR);
        // 3.得到课程相关信息
        CourseOrderInfoVo courseOrderInfoVo = JSON.parseObject(JSON.toJSONString(infoTmp), CourseOrderInfoVo.class);
        List<CourseInfoVo> courseInfos = courseOrderInfoVo.getCourseInfos();
        BigDecimal totalAmount = courseOrderInfoVo.getTotalAmount();
        // 4.保存课程主订单
        CourseOrder courseOrder = new CourseOrder();
        Date date = new Date();
        courseOrder.setCreateTime(date);
        String orderNo = CodeGenerateUtils.generateOrderSn(loginId);
        courseOrder.setOrderNo(orderNo);
        courseOrder.setTotalAmount(totalAmount);
        courseOrder.setTotalCount(courseIds.size());
        courseOrder.setStatusOrder(CourseOrder.WAITE_PAY);
        courseOrder.setUserId(loginId);
        courseOrder.setVersion(0);
        courseOrder.setPayType(payType);
        String titleTmp = "购买课程 [%s] , 支付[%s] 元";
        String courseNames = courseInfos.stream().map(c -> c.getCourse().getName()).collect(Collectors.joining(","));
        String title = String.format(titleTmp,courseNames,totalAmount);
        courseOrder.setTitle(title);
//        insert(courseOrder);
        // 5.保存订单快照
        courseInfos.forEach(e->{
            Course course = e.getCourse();
            CourseMarket courseMarket = e.getCourseMarket();
            CourseOrderItem courseOrderItem = new CourseOrderItem();
//            courseOrderItem.setOrderId(courseOrder.getId());
            courseOrderItem.setAmount(courseMarket.getPrice());
            courseOrderItem.setCount(1);
            courseOrderItem.setCreateTime(date);
            courseOrderItem.setCourseId(course.getId());
            courseOrderItem.setCourseName(course.getName());
            courseOrderItem.setCoursePic(course.getPic());
            courseOrderItem.setVersion(0);
            courseOrderItem.setOrderNo(orderNo);
//            courseOrderItemService.insert(courseOrderItem);
            courseOrder.getCourseOrderItems().add(courseOrderItem);
        });
        CourseOrderPayBo courseOrderPayBo = new CourseOrderPayBo();
        BeanUtils.copyProperties(courseOrder,courseOrderPayBo);

        Message<CourseOrderPayBo> message = MessageBuilder.withPayload(courseOrderPayBo).build();
        // 6.调用支付服务，发起支付
        // amount、pay_type、order_no、user_id、subject
        //使用事务消息
        rocketMQTemplate.sendMessageInTransaction(
                "tx-course-order-pay-producer-group",
                "course-order-pay-topic:course-order-pay-tag",
                message,courseOrder);
        // 7.定时30分钟，检查支付是否成功

        return orderNo;
    }

    /**
     * 保存主订单和订单快照
     * @param courseOrder
     */
    @Override
    public void insertCourseOrderAndCourseOrderItem(CourseOrder courseOrder) {
        //业务校验，课程订单必须不存在
        CourseOrder selectOrder = selectByOrderNo(courseOrder.getOrderNo());
        AssertUtil.isNull(selectOrder,GlobalExceptionEnum.ERROR);
        //保存课程订单
        insert(courseOrder);
        List<CourseOrderItem> courseOrderItems = courseOrder.getCourseOrderItems();
        courseOrderItems.forEach(e->e.setOrderId(courseOrder.getId()));
        //保存课程订单快照
        courseOrderItemService.insertBatch(courseOrderItems);
    }

    @Override
    public CourseOrder selectByOrderNo(String orderNo) {
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no", orderNo);
        return selectOne(wrapper);
    }

}
